﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security.Permissions;
using System.Threading;

namespace Netbits.Common.Threading
{
	/// <summary>
	/// Compiled Lock Type. 
	/// </summary>
	public enum LockType : byte
	{
		/// <summary>
		/// Define the my own LOCK handling. Only for Mono. 
		/// </summary>
		Own,
		/// <summary>
		/// Define the default ReaderWriterLockSlim implementation
		/// </summary>
		ReaderWriterLockSlim
	}

	/// <summary>
	/// This LOCK class represent four types of locks.
	/// 
	/// Type					Preprocessor-Flag
	/// Speed-Version 			USE_LOCK_SPEED (use the Thread-Static State-list. but if a lock-instance dispose the state-data are alive!)
	/// FastCache				USE_LOCK_FAST_STATE_CACHE (is the fastest way to get the thread-statistic. but use 4*4*64 Byte per Lock-Instance
	/// My Own Lock				USE_LOCK_OWN
	/// ReaderWriterLockSlim	!USE_LOCK_OWN
	/// 
	/// MyOwnLock vs ReaderWriterLockSlim
	///    MyOwn version default constructor define LockRecursionPolicy.SupportsRecursion! so recursions are supported!
	///    All other features from the original ReaderWriterLockSlim are implemented.
	///    Functions "Read/Write/Upgrade" creates a new IDisposable Class end Enter the lock. After disposing the class the lock are released.
	///		You can use
	///		<code>
	///			Lock l = new Lock();
	///			using( l.Read() )
	///			{
	///				// do something in read-lock mode
	///			}
	///		</code>
	/// 
	/// Why i create this class?
	/// On Mono http://www.mono-project.com the ReaderWriterLockSlim Class has many bugs. (2013.11.09)
	/// I would use a fast-switch from my, monitor and ReaderWriterLockSlim implementation because i create this class.
	/// </summary>
	[HostProtectionAttribute( SecurityAction.LinkDemand, MayLeakOnAbort = true )]
	[HostProtectionAttribute( SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true )]
	public sealed class Lock : IDisposable
	{
		#region Private Classes

		#region Class ReadLockTocken

		/// <summary>
		/// This class create a read-lock token.
		/// After Dispose this class the read-lock was released.
		/// </summary>
		sealed class ReadLockToken : IDisposable
		{
			#region Private Variables

			Lock _Sync;

			#endregion

			#region Constructor

			public ReadLockToken( Lock Sync_ )
			{
				Sync_.EnterReadLock();
				_Sync = Sync_;
			}

			#endregion

			#region IDisposable

			public void Dispose()
			{
				if( _Sync != null )
				{
					_Sync.ExitReadLock();
					_Sync = null;
				}
				GC.SuppressFinalize( this );
			}

			#endregion
		}

		#endregion

		#region Class WriteLockToken

		/// <summary>
		/// This class create a write-lock token.
		/// After Dispose this class the write-lock was released.
		/// </summary>
		sealed class WriteLockToken : IDisposable
		{
			#region Private Variables

			Lock _Sync;

			#endregion

			#region Constructor

			public WriteLockToken( Lock Sync_ )
			{
				Sync_.EnterWriteLock();
				_Sync = Sync_;
			}

			#endregion

			#region IDisposable

			public void Dispose()
			{
				if( _Sync != null )
				{
					_Sync.ExitWriteLock();
					_Sync = null;
				}

				GC.SuppressFinalize( this );
			}

			#endregion
		}

		#endregion

		#region Class UpgradeLockToken

		/// <summary>
		/// This class create an upgradeable-reader-lock token.
		/// After Dispose this class the upgradeable-reader-lock was released.
		/// </summary>
		sealed class UpgradeLockToken : IDisposable
		{
			#region Private Variables

			Lock _Sync;

			#endregion

			#region Constructor

			public UpgradeLockToken( Lock Sync_ )
			{
				Sync_.EnterUpgradeableReadLock();
				_Sync = Sync_;
			}

			#endregion

			#region IDisposable

			public void Dispose()
			{
				if( _Sync != null )
				{
					_Sync.ExitUpgradeableReadLock();
					_Sync = null;
				}

				GC.SuppressFinalize( this );
			}

			#endregion
		}

		#endregion

		#region Class ThreadLockState

#if USE_LOCK_OWN
		//[Flags]
		enum LockState
		{
			None			= 0,					// No Lock acquired 
			Read			= 1,					// Read-Lock acquired
			Write			= 2,					// Write-Lock acquired
			Upgrade			= 4
		}

		/// <summary>
		/// This class hold the thread-state an his counter.
		/// </summary>
		class ThreadLockState
		{
			public LockState State = LockState.None;		// Hold the state of the current thread
			public int RecursiveReaderCount;				// Hold the count of recursive-read-locks for the current thread
			public int RecursiveWriterCount;				// Hold the count of recursive-write-locks for the current thread
			public int RecursiveUpgradeCount;				// Hold the count of recursive-write-locks for the current thread
		}
#endif
		#endregion

		#endregion

		#region Private Variables

		readonly object _MonitorLock;
		int _ReadCount;
		int _WaitReadCount;
		int _WaitWriteCount;
		int _WaitUpgradeCount;

#if USE_LOCK_OWN
		const int LOCKSTATE_NONE = 0;
		const int LOCKSTATE_READ = 1;
		const int LOCKSTATE_WRITE = 2;
		const int LOCKSTATE_UPGRADE = 3;

		LockRecursionPolicy _Policy = LockRecursionPolicy.SupportsRecursion;
		int _State = LOCKSTATE_NONE;
		bool _Disposed;
#if USE_LOCK_SPEED
		[ThreadStatic]
		static IDictionary<int, ThreadLockState> _States;
		static int _LockIdPool = int.MinValue;
		int _LockId;
#else
#if DEBUG
		static int _LockIdPool = int.MinValue;
		int _LockId;
#endif
		IDictionary<int, ThreadLockState> _States;
#endif

#if USE_LOCK_FAST_STATE_CACHE
		ThreadLockState[] fastStateCache = new ThreadLockState[64];
#endif

#if !USE_LOCK_SPEED
		int _SyncLock = 0;
		int _SyncLockCounter = 0;
		int _SyncWriteCounter = 0;
#endif
		static Stopwatch _TimeoutHandler = Stopwatch.StartNew();
        LockType _Type = LockType.Own;
		ManualResetEventSlim _WaitWriteLockDone;
		ManualResetEventSlim _WaitReadLockDone;
		ManualResetEventSlim _WaitUpgradeLockDone;
#else
#if DEBUG
		static int _LockIdPool = 0;
		int _LockId;
#endif
		LockType _Type = LockType.ReaderWriterLockSlim;
		ReaderWriterLockSlim _Lock;
#endif
		#endregion

		#region Constructor

		/// <summary>
		/// Create a new instance of the Lock class with default SupportsRecursion property
		/// </summary>
		public Lock() : this( LockRecursionPolicy.SupportsRecursion )
		{
		}

		/// <summary>
		/// Create a new instance of the lock class with default SupportsRecursion property with specified UseMonitorLock.
		/// </summary>
		/// <param name="UseMonitorLock_">If true Montor.Enter/Leave used to lock this instance</param>
		public Lock( bool UseMonitorLock_ ) : this( LockRecursionPolicy.SupportsRecursion, UseMonitorLock_ )
		{
		}

		/// <summary>
		/// Create a new instance of the Lock class with specifying the RecursionPolicy
		/// </summary>
		/// <param name="Policy_">Specifies the lock recursion policy</param>
		public Lock( LockRecursionPolicy Policy_ ) : this( Policy_, false )
		{
		}

		/// <summary>
		/// Create a new instance of the Lock class with specifying the RecursionPolicy and specified UseMonitorLock
		/// </summary>
		/// <param name="Policy_">Specifies the lock recursion policy</param>
		/// <param name="UseMonitorLock_">If true Montor.Enter/Leave used to lock this instance</param>
		public Lock( LockRecursionPolicy Policy_, bool UseMonitorLock_ )
		{
#if USE_LOCK_OWN
#if USE_LOCK_SPEED
			_LockId = Interlocked.Increment( ref _LockIdPool );
#else
#if DEBUG
			_LockId = Interlocked.Increment( ref _LockIdPool );
#endif
			_MonitorLock = new object();
			_States = new Dictionary<int, ThreadLockState>();
#endif
			_Policy = Policy_;
			_WaitWriteLockDone = new ManualResetEventSlim( true );
			_WaitReadLockDone = new ManualResetEventSlim( true );
			_WaitUpgradeLockDone = new ManualResetEventSlim( true );
#else
#if DEBUG
			_LockId = Interlocked.Increment( ref _LockIdPool );
#endif
			if( UseMonitorLock_ )
				_MonitorLock = new object();
			else
				_Lock = new ReaderWriterLockSlim( Policy_ );
#endif
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Return the recursion policy for the current lock instance
		/// </summary>
		public LockRecursionPolicy RecursionPolicy
		{
			get
			{
#if USE_LOCK_OWN
				return _Policy;
#else
				return _Lock.RecursionPolicy;
#endif
			}
		}

		/// <summary>
		/// Return the compiled Lock-Type
		/// </summary>
		public LockType Type
		{
			get
			{
				return _Type;
			}
		}

		/// <summary>
		/// Return the number of total Read-Locks
		/// </summary>
		public int CurrentReadCount
		{
			get
			{
#if USE_LOCK_OWN
                return _ReadCount;
#else
				if( _MonitorLock != null )
					return _ReadCount;

				return _Lock.CurrentReadCount;
#endif
			}
		}

		/// <summary>
		/// Returns if the current thread has entered the read-lock
		/// </summary>
		public bool IsReadLockHeld
		{
			get
			{
#if USE_LOCK_OWN
				return _GetState().State.HasFlag( LockState.Read );
#else
				if( _MonitorLock != null )
					throw new NotSupportedException();

				return _Lock.IsReadLockHeld;
#endif
			}
		}

		/// <summary>
		/// Returns if the current thread has entered the upgradeable-read-lock
		/// </summary>
		public bool IsUpgradeableReadLockHeld
		{
			get
			{
#if USE_LOCK_OWN
				return _GetState().State.HasFlag( LockState.Upgrade );
#else
				if( _MonitorLock != null )
					throw new NotSupportedException();
				return _Lock.IsUpgradeableReadLockHeld;
#endif
			}
		}

		/// <summary>
		/// Returns if the current thread has entered the write-lock
		/// </summary>
		public bool IsWriteLockHeld
		{
			get
			{
#if USE_LOCK_OWN
				return _GetState().State.HasFlag( LockState.Write );
#else
				if( _MonitorLock != null )
					throw new NotSupportedException();
				return _Lock.IsWriteLockHeld;
#endif
			}
		}

		/// <summary>
		/// Returns the count of recursive read-locks for the current thread
		/// </summary>
		public int RecursiveReadCount
		{
			get
			{
#if USE_LOCK_OWN
				return _GetState().RecursiveReaderCount;
#else
				if( _MonitorLock != null )
					throw new NotSupportedException();
				return _Lock.RecursiveReadCount;
#endif
			}
		}

		/// <summary>
		/// Returns the count of recursive upgradeable-read-locks for the current thread
		/// </summary>
		public int RecursiveUpgradeCount
		{
			get
			{
#if USE_LOCK_OWN
				return _GetState().RecursiveUpgradeCount;
#else
				if( _MonitorLock != null )
					throw new NotSupportedException();
				return _Lock.RecursiveUpgradeCount;
#endif
			}
		}

		/// <summary>
		/// Returns the count of recursive write-locks for the current thread
		/// </summary>
		public int RecursiveWriteCount
		{
			get
			{
#if USE_LOCK_OWN
				return _GetState().RecursiveWriterCount;
#else
				if( _MonitorLock != null )
					throw new NotSupportedException();
				return _Lock.RecursiveWriteCount;
#endif
			}
		}

		#endregion

		#region Public Functions

		/// <summary>
		/// Create a read-lock and return a disposable token
		/// </summary>
		/// <returns>The disposable token</returns>
		public IDisposable Read()
		{
			return new ReadLockToken( this );
		}

		/// <summary>
		/// Create a upgradeable-reader-lock  and return a disposable token
		/// </summary>
		/// <returns>The disposable token</returns>
		public IDisposable Upgrade()
		{
			return new UpgradeLockToken( this );
		}

		/// <summary>
		/// Create a write-lock and return a disposable token
		/// </summary>
		/// <returns>The disposable token</returns>
		public IDisposable Write()
		{
			return new WriteLockToken( this );
		}

		/// <summary>
		/// Enter the lock in read-mode.
		/// </summary>
		public void EnterReadLock()
		{
#if USE_LOCK_OWN
			TryEnterReadLock( -1 );
#else
			if( _MonitorLock != null )
				TryEnterReadLock( -1 );
			else
				_Lock.EnterReadLock();
#endif
		}

		/// <summary>
		/// Tries to enter the lock in read-mode, with a time-out
		/// </summary>
		/// <param name="Timeout_">The time to wait</param>
		/// <returns>true if entered read-mode, otherwise false</returns>
		public bool TryEnterReadLock( TimeSpan Timeout_ )
		{
#if USE_LOCK_OWN
			return TryEnterReadLock( CheckTimeout( Timeout_ ) );
#else
			if( _MonitorLock != null )
				return TryEnterReadLock( CheckTimeout( Timeout_ ) );

			return _Lock.TryEnterReadLock( Timeout_ );
#endif
		}

		/// <summary>
		/// Tries to enter the lock in read-mode, with a time-out in ms
		/// </summary>
		/// <param name="Timeout_">The time to wait in milliseconds. -1 to wait indefinitely</param>
		/// <returns>true if entered read-mode, otherwise false</returns>
		public bool TryEnterReadLock( int Timeout_ )
		{
			if( _MonitorLock != null )
			{
				Interlocked.Increment( ref _WaitReadCount );
				Monitor.Enter( _MonitorLock );
				Interlocked.Increment( ref _ReadCount );
				Interlocked.Decrement( ref _WaitReadCount );
				return true;
			}

#if USE_LOCK_OWN
			Interlocked.Increment( ref _WaitReadCount );

			ThreadLockState tls = _GetState();
			if( tls.State != LockState.None )
			{
				if( _Policy == LockRecursionPolicy.NoRecursion )
					throw new LockRecursionException();

				_SetReadLock( tls );
				return true;
			}

			long start = Timeout_ == -1 ? 0 : _TimeoutHandler.ElapsedMilliseconds;
			while( Timeout_ == -1 || (_TimeoutHandler.ElapsedMilliseconds - start) < Timeout_ )
			{
				if( _State != LOCKSTATE_NONE && _WaitWriteCount > 0 )
					continue;

				if( !_WaitWriteLockDone.IsSet )
				{
					if( !_WaitWriteLockDone.Wait( _ComputeTimeout( Timeout_, start ) ) )
						return false;
					continue;
				}

				if( Interlocked.CompareExchange( ref _State, LOCKSTATE_READ, LOCKSTATE_NONE ) != LOCKSTATE_NONE )
					continue;

				Interlocked.Increment( ref _ReadCount );
				_SetReadLock( tls );
				return true;
			}

			return false;
#else
			return _Lock.TryEnterReadLock( Timeout_ );
#endif
		}

		/// <summary>
		/// Leave the lock in read-mode. 
		/// </summary>
		public void ExitReadLock()
		{
			if( _MonitorLock != null )
			{
				Interlocked.Decrement( ref _ReadCount );
				Monitor.Exit( _MonitorLock );
				return;
			}

#if USE_LOCK_OWN
			ThreadLockState tls = _GetState();
			if( tls.RecursiveReaderCount == 0 )
				throw new SynchronizationLockException( "you can't release read-lock mode. current thread not entered read-lock" );

			--tls.RecursiveReaderCount;
			if( tls.RecursiveReaderCount == 0 )
			{
				tls.State ^= LockState.Read;
				if( _ReadCount > 1 )
					return;
				
				// OK we are the last that has entered the read-lock. so we can enter to the state NONE
				if( tls.State == LockState.None )
				{
					Interlocked.Decrement( ref _ReadCount );
					Interlocked.Exchange( ref _State, LOCKSTATE_NONE );
					_WaitReadLockDone.Set();
				}
			}
#else
			_Lock.ExitReadLock();
#endif

#if DEBUG_LOCK
            System.Console.WriteLine( "END EXIT READLOCK" );
            PrintStateInfo();
#endif
		}

		/// <summary>
		/// Enter the lock in write-mode.
		/// </summary>
		public void EnterWriteLock()
		{
#if USE_LOCK_OWN
			TryEnterWriteLock( -1 );
#else
			if( _MonitorLock != null )
				TryEnterWriteLock( -1 );
			else
				_Lock.EnterWriteLock();
#endif
		}

		/// <summary>
		/// Tries to enter the lock in write-mode, with a time-out
		/// </summary>
		/// <param name="Timeout_">The time to wait</param>
		/// <returns>true if entered in write-mode, otherwise false</returns>
		public bool TryEnterWriteLock( TimeSpan Timeout_ )
		{
#if USE_LOCK_OWN
			return TryEnterWriteLock( CheckTimeout( Timeout_ ) );
#else
			if( _MonitorLock != null )
				return TryEnterWriteLock( CheckTimeout( Timeout_ ) );

			return _Lock.TryEnterWriteLock( Timeout_ );
#endif
		}

		/// <summary>
		/// Tries to enter the lock in write-mode, with a time-out in milliseconds
		/// </summary>
		/// <param name="Timeout_">The time to wait in milliseconds. -1 to wait indefinitely</param>
		/// <returns>true if entered write-mode, otherwise false</returns>
		public bool TryEnterWriteLock( int Timeout_ )
		{
			if( _MonitorLock != null )
			{
				Interlocked.Increment( ref _WaitWriteCount );
				Monitor.Enter( _MonitorLock );
				Interlocked.Decrement( ref _WaitWriteCount );
				return true;
			}

#if USE_LOCK_OWN
			Interlocked.Increment( ref _WaitWriteCount );
			
			ThreadLockState tls = _GetState();
			if( tls.State != LockState.None )
			{
				if( _Policy == LockRecursionPolicy.NoRecursion )
					throw new LockRecursionException();

				if( tls.State == LockState.Read )
					throw new SynchronizationLockException();

				_SetWriteLock( tls );
				return true;
			}

			long start = Timeout_ == -1 ? 0 : _TimeoutHandler.ElapsedMilliseconds;
			while( Timeout_ == -1 || (_TimeoutHandler.ElapsedMilliseconds - start) < Timeout_ )
			{
				if( _State != LOCKSTATE_NONE && (_WaitReadCount > 0 || _WaitUpgradeCount > 0) )
					continue;

				if( !_WaitReadLockDone.IsSet )
				{
					if( !_WaitReadLockDone.Wait( _ComputeTimeout( Timeout_, start ) ) )
						return false;
					continue;
				}

				if( !_WaitUpgradeLockDone.IsSet )
				{
					if( !_WaitUpgradeLockDone.Wait( _ComputeTimeout( Timeout_, start ) ) )
						return false;
					continue;
				}

				if( !_WaitWriteLockDone.IsSet )
				{
					if( !_WaitWriteLockDone.Wait( _ComputeTimeout( Timeout_, start ) ) )
						return false;
					continue;
				}

				if( Interlocked.CompareExchange( ref _State, LOCKSTATE_WRITE, LOCKSTATE_NONE ) != LOCKSTATE_NONE )
					continue;

				_SetWriteLock( tls );
				return true;
			}

			return false;
#else
			return _Lock.TryEnterWriteLock( Timeout_ );
#endif
		}

		/// <summary>
		/// Leave the lock in write-mode
		/// </summary>
		public void ExitWriteLock()
		{
			if( _MonitorLock != null )
			{
				Monitor.Exit( _MonitorLock );
				return;
			}

#if USE_LOCK_OWN
			ThreadLockState tls = _GetState();
			if( tls.RecursiveWriterCount == 0 )
				throw new SynchronizationLockException( "you can't release the write-lock. current thread not entered write-lock" );

			--tls.RecursiveWriterCount;
			if( tls.RecursiveWriterCount == 0 )
			{
				tls.State ^= LockState.Write;

				if( tls.State == LockState.None )
				{
					Interlocked.Exchange( ref _State, LOCKSTATE_NONE );
					_WaitWriteLockDone.Set();
				}
			}
#else
			_Lock.ExitWriteLock();
#endif
		}

		/// <summary>
		/// Enter the lock in upgradeable-read-mode.
		/// </summary>
		public void EnterUpgradeableReadLock()
		{
#if USE_LOCK_OWN
			TryEnterUpgradeableReadLock( -1 );
#else
			if( _MonitorLock != null )
				TryEnterUpgradeableReadLock( -1 );
			else
				_Lock.EnterUpgradeableReadLock();
#endif
		}

		/// <summary>
		/// Tries to enter the lock in upgradeable-read-mode, with a time-out
		/// </summary>
		/// <param name="Timeout_">The time to wait</param>
		/// <returns>true if entered upgradeable-read-mode, otherwise false</returns>
		public bool TryEnterUpgradeableReadLock( TimeSpan Timeout_ )
		{
#if USE_LOCK_OWN
			return TryEnterUpgradeableReadLock( CheckTimeout( Timeout_ ) );
#else
			if( _MonitorLock != null )
				return TryEnterUpgradeableReadLock( CheckTimeout( Timeout_ ) );

			return _Lock.TryEnterUpgradeableReadLock( Timeout_ );
#endif
		}

		/// <summary>
		/// Tries to enter the lock in upgradeable-read-mode, with a time-out in milliseconds
		/// </summary>
		/// <param name="Timeout_">The time to wait in milliseconds. -1 to wait indefinitely</param>
		/// <returns>true if entered upgradeable-read-mode, otherwise false</returns>
		public bool TryEnterUpgradeableReadLock( int Timeout_ )
		{
			if( _MonitorLock != null )
			{
				Interlocked.Increment( ref _WaitUpgradeCount );
				Monitor.Enter( _MonitorLock );
				Interlocked.Decrement( ref _WaitUpgradeCount );
				return true;
			}

#if USE_LOCK_OWN
			Interlocked.Increment( ref _WaitUpgradeCount );
			
			ThreadLockState tls = _GetState();
			if( tls.State != LockState.None )
			{
				if( tls.State == LockState.Read )
					throw new SynchronizationLockException();

				if( _Policy == LockRecursionPolicy.NoRecursion )
					throw new LockRecursionException();

				_SetUpgradeLock( tls );
				return true;
			}

			long start = Timeout_ == -1 ? 0 : _TimeoutHandler.ElapsedMilliseconds;
			while( Timeout_ == -1 || (_TimeoutHandler.ElapsedMilliseconds - start) < Timeout_ )
			{
				if( _State != LOCKSTATE_NONE && (_WaitUpgradeCount > 0 || _WaitWriteCount > 0) )
					continue;

				if( !_WaitUpgradeLockDone.IsSet )
				{
					if( !_WaitUpgradeLockDone.Wait( _ComputeTimeout( Timeout_, start ) ) )
						return false;
					continue;
				}

				if( !_WaitWriteLockDone.IsSet )
				{
					if( !_WaitWriteLockDone.Wait( _ComputeTimeout( Timeout_, start ) ) )
						return false;
					continue;
				}

				if( Interlocked.CompareExchange( ref _State, LOCKSTATE_UPGRADE, LOCKSTATE_NONE ) != LOCKSTATE_NONE )
					continue;

				_SetUpgradeLock( tls );
				return true;
			}
			return false;
#else
			return _Lock.TryEnterUpgradeableReadLock( Timeout_ );
#endif
		}

		/// <summary>
		/// Leave the lock in upgradeable-read-mode.
		/// </summary>
		public void ExitUpgradeableReadLock()
		{
			if( _MonitorLock != null )
			{
				Monitor.Exit( _MonitorLock );
				return;
			}

#if USE_LOCK_OWN
			ThreadLockState tls = _GetState();
			if( tls.RecursiveUpgradeCount == 0 )
				throw new SynchronizationLockException( "you can't release the upgrade-reader-lock. current thread not entered" );

			--tls.RecursiveUpgradeCount;
			if( tls.RecursiveUpgradeCount == 0 )
			{
				tls.State ^= LockState.Upgrade;

				if( tls.State == LockState.None )
				{
					Interlocked.Exchange( ref _State, LOCKSTATE_NONE );
					_WaitUpgradeLockDone.Set();
				}
			}
#else
			_Lock.ExitUpgradeableReadLock();
#endif
		}

		#endregion

		#region Private Functions

		static int CheckTimeout( TimeSpan Timeout_ )
		{
			try
			{
				return checked( (int)Timeout_.TotalMilliseconds );
			}
			catch( OverflowException )
			{
				throw new ArgumentOutOfRangeException( "Timeout_" );
			}
		}

#if USE_LOCK_OWN
		void _SetReadLock( ThreadLockState State_ )
		{
			if( State_.State == LockState.None )
			{
				if( _WaitReadLockDone.IsSet )
					_WaitReadLockDone.Reset();
			}

			Interlocked.Decrement( ref _WaitReadCount );
			if( !State_.State.HasFlag( LockState.Read ) )
				State_.State ^= LockState.Read;
			++State_.RecursiveReaderCount;
		}

		void _SetUpgradeLock( ThreadLockState State_ )
		{
			if( State_.State == LockState.None )
			{
				if( _WaitUpgradeLockDone.IsSet )
					_WaitUpgradeLockDone.Reset();
			}

			Interlocked.Decrement( ref _WaitUpgradeCount );
			if( !State_.State.HasFlag( LockState.Upgrade ) )
				State_.State ^= LockState.Upgrade;
			++State_.RecursiveUpgradeCount;
		}

		void _SetWriteLock( ThreadLockState State_ )
		{
			if( State_.State == LockState.None )
			{
				if( _WaitWriteLockDone.IsSet )
					_WaitWriteLockDone.Reset();
			}

			Interlocked.Decrement( ref _WaitWriteCount );
			if( !State_.State.HasFlag( LockState.Write ) )
				State_.State ^= LockState.Write;
			++State_.RecursiveWriterCount;
		}

		static int _ComputeTimeout( int Timeout_, long Start_ )
		{
			return Timeout_ == -1 ? -1 : (int)Math.Max( _TimeoutHandler.ElapsedMilliseconds - Start_ - Timeout_, 1 );
		}

		ThreadLockState _GetState()
		{
			if( _Disposed )
				throw new ObjectDisposedException( "Lock" );

#if USE_LOCK_FAST_STATE_CACHE
			int tid = Thread.CurrentThread.ManagedThreadId;
			if( tid < fastStateCache.Length )
				return fastStateCache[tid] == null ? (fastStateCache[tid] = new ThreadLockState()) : fastStateCache[tid];
#endif
#if USE_LOCK_SPEED
			ThreadLockState tls;

			if( _States == null )
				_States = new Dictionary<int, ThreadLockState>();

			if( !_States.TryGetValue( _LockId, out tls ) )
				_States[_LockId] = tls = new ThreadLockState();

			return tls;
#else
			if( _SyncLockCounter == 1 || _SyncWriteCounter > 0 )
			{
				SpinWait sw = new SpinWait();
				while( _SyncLockCounter != 0 && _SyncWriteCounter > 0 )
				{
					sw.SpinOnce();
				}
			}

			ThreadLockState tls;
			Interlocked.Increment( ref _SyncLock );
			if( !_States.TryGetValue( Thread.CurrentThread.ManagedThreadId, out tls ) )
			{
				Interlocked.Increment( ref _SyncWriteCounter );

				SpinWait sw = new SpinWait();
				while( Interlocked.CompareExchange( ref _SyncLockCounter, 1, 0 ) != 0 )
					sw.SpinOnce();

				while( _SyncLock > _SyncWriteCounter )
					sw.SpinOnce();

				_States[Thread.CurrentThread.ManagedThreadId] = tls = new ThreadLockState();

				Interlocked.Decrement( ref _SyncWriteCounter );
				Interlocked.Exchange( ref _SyncLockCounter, 0 );
			}
			Interlocked.Decrement( ref _SyncLock );
			return tls;
#endif
		}
#endif
		#endregion

		#region Overrides

		/// <summary>
		/// Set the generic information as a string.
		/// </summary>
		/// <returns>Generic information</returns>
		public override string ToString()
		{
#if USE_LOCK_OWN
			ThreadLockState tls = _GetState();
#if DEBUG
			int id = _LockId;
#else 
			int id = 0;
#endif
			return string.Format( "[{0}-{1}] rlc:{2}, wlc:{3}, ulc:{4}, wrc:{5}, wwc:{6}, wuc:{7}",
				id, _State, _ReadCount, tls.RecursiveWriterCount, tls.RecursiveUpgradeCount, _WaitReadCount, _WaitWriteCount, _WaitUpgradeCount );
#else
			return _Lock.ToString();
#endif
		}

		#endregion

		#region IDisposeable

		/// <summary>
		/// Dispose the object and clear all resources.
		/// </summary>
		public void Dispose()
		{
#if USE_LOCK_OWN
			_Disposed = true;
#else
			_Lock.Dispose();
#endif
		}

		#endregion
	}
}